use std::thread;
use std::time::Duration;

struct Cacher1<T>
where T: Fn(u32) -> u32
{
    calculation: T,
    value: Option<u32>,
}

impl <T> Cacher1<T>
where T: Fn(u32) -> u32
{
    fn new(calculation: T) -> Cacher1<T> {
        Cacher1 {
            calculation,
            value: None,
        }
    }

    fn value(&mut self, arg: u32) -> u32 {

        match self.value {
            Some(v) => v,
            None => {
                let v = (self.calculation)(arg);
                self.value = Some(v);
                v
            },
        }
    }
}

pub fn generate_workout(intensity: u32, random_number: u32) {

    let mut expensive_result = Cacher1::new(|num| {
        println!("1calculating slowly...");
        thread::sleep(Duration::from_secs(2));
        num
    });

    if intensity < 25 {
        println!(
            "1Today, do {} pushups!",
            expensive_result.value(intensity)
        );
        println!(
            "1Next, do {} situps!",
            expensive_result.value(intensity)
        );
    } else {
        if random_number == 3 {
            println!("1Take a break today! Remember to stay hydrated!");
        } else {
            println!(
                "1Today, run for {} minutes!",
                expensive_result.value(intensity)
            );
        }
    }
}
pub fn test() {
    let mut expensive_result = Cacher1::new(|num| num);
    println!("cacher1 first {}", expensive_result.value(1));
    println!("cacher1 second {}", expensive_result.value(12));
}